/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.debugger.debug; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ResourceBundle; import javax.swing.SwingUtilities; import sun.tools.debug.*; import org.openide.TopManager; import org.openide.util.NbBundle; import org.openide.debugger.Watch; import org.openide.debugger.DebuggerNotFoundException; import org.netbeans.modules.debugger.support.VariableImpl; import org.netbeans.modules.debugger.support.AbstractVariable; import org.netbeans.modules.debugger.support.util.Validator; import org.netbeans.modules.debugger.support.util.Protector; import org.netbeans.modules.debugger.support.util.Utils; /** * * * @author Jan Jancura * @version 0.17, Apr 29, 1998 */ public class ToolsVariable extends VariableImpl { /** generated Serialized Version UID */ static final long serialVersionUID = -4908841115435797749L; /** bundle to obtain text information from */ private static ResourceBundle bundle = NbBundle.getBundle (ToolsVariable.class); //static int num = 0; //int myNum; // variables ......................................................................... /** Variables parentObject & (name | index) identifies variable. */ private transient RemoteObject parentObject; /** Current value - used for getFields (). */ protected transient RemoteValue remoteValue; /** Cashing of children variables */ private transient RemoteObject oldObject; /** Cashing of children variables */ private transient AbstractVariable[] oldFields; protected transient ToolsDebugger debugger; // init ............................................................................... /** * Non public constructor. */ ToolsVariable (ToolsDebugger debugger, boolean validate) { super (debugger, validate ? debugger.getValidator () : null); this.debugger = debugger; } /** * Non public constructor called from the ToolsVariable only. */ ToolsVariable ( ToolsDebugger debugger, RemoteObject parentObject, RemoteField remoteField ) { this (debugger, true); update (remoteField, parentObject); } /** * Non public constructor called from the TheThread only. Creates local variable. */ ToolsVariable ( ToolsDebugger debugger, String name, RemoteValue value, String type ) { this (debugger, false); update (name, value, type); } /** * Non public constructor called from the AbstractVariable only. */ ToolsVariable ( ToolsDebugger debugger, RemoteArray array, String parentName, int index, String type ) { this (debugger, true); update (parentName, array, index, type); } private void readObject (java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { in.defaultReadObject (); try { debugger = (ToolsDebugger) TopManager.getDefault ().getDebugger (); } catch (DebuggerNotFoundException e) { throw new java.io.IOException (); } } // AbstractVariable implementation ............................................................ /** * Setter that allows to change value of the watched variable. * * @param value text representation of the value * @exception DebuggerException if the value cannot be changed or the * string does not represent valid value */ public void setAsText (final String value) { final String type = this.type; final String name = this.name; final PropertyChangeSupport pcs = this.pcs; new Protector ("ToolsVariable.setAsText") { // NOI18N public Object protect () throws Exception { if (parentObject == null) throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Static") ); if (type.equals ("int")) { // NOI18N try { parentObject.setField (name, Integer.parseInt (value)); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("byte")) { // NOI18N try { parentObject.setField (name, Byte.parseByte (value)); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("short")) { // NOI18N try { parentObject.setField (name, Short.parseShort (value)); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("boolean")) { // NOI18N Boolean b = Boolean.valueOf (value); if (b == null) throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); try { parentObject.setField (name, b.booleanValue ()); setValue (value); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("char")) { // NOI18N if (value.length () < 1) throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); try { parentObject.setField (name, value.charAt (0)); setValue (value); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("double")) { // NOI18N try { parentObject.setField (name, new Double (value).doubleValue ()); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("float")) { // NOI18N try { parentObject.setField (name, new Float (value).floatValue ()); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else if (type.equals ("long")) { // NOI18N try { parentObject.setField (name, Long.parseLong (value)); setValue (value); } catch (NumberFormatException e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Wrong_format") ); } catch (Exception e) { throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Value_cannt_be_set") ); } } else throw Utils.localizeException ( new IllegalArgumentException (), bundle.getString ("EXC_Unsupported_type") ); return null; } }.wait (debugger.synchronizer, debugger.killer); // deadlock prevention if (pcs != null) pcs.firePropertyChange (Watch.PROP_AS_TEXT, null, null); } /** * If this AbstractVariable object represents instance of some class or array this method * returns variables (static and non-static) of this object. * * @return variables (static and non-static) of this object. */ public AbstractVariable[] getFields () { if (debugger.synchronizer == null) return new ToolsVariable [0]; final String type; if (remoteValue instanceof RemoteArray) type = innerType.substring (0, innerType.length () - 2); else type = innerType; final String name = this.name; return (AbstractVariable[]) new Protector ("ToolsVariable.getFields") { // NOI18N public Object protect () throws Exception { //S ystem.out.println ("getFields " + remoteValue + " " + oldObject); // NOI18N if ((remoteValue == null) || !(remoteValue instanceof RemoteObject) ) { //S ystem.out.println ("getFields prim."); // NOI18N return new ToolsVariable [0]; } if ((oldObject != null) && oldObject.equals (remoteValue)) { //S ystem.out.println ("getFields return old " + oldFields + " " + oldFields.length); // NOI18N // int i, k = oldFields.length; // for (i = 0; i < k; i++) oldFields [i].validate (); return oldFields; } try { AbstractVariable[] variable; RemoteObject remoteObject = (RemoteObject)remoteValue; if (remoteValue instanceof RemoteArray) { RemoteArray array = (RemoteArray) remoteValue; RemoteValue[] values = array.getElements (); int i, k = values.length; variable = new AbstractVariable [k]; for (i = 0; i < k; i++) variable [i] = new ToolsVariable ( debugger, array, name, i, type ); //S ystem.out.println ("getFields return array " + variable + " " + variable.length); // NOI18N } else { RemoteField[] remoteField = ((RemoteObject)remoteValue).getFields (); RemoteClass remoteClass = remoteObject.getClazz (); RemoteField[] sRemoteField = remoteClass.getFields (); variable = new AbstractVariable [remoteField.length + sRemoteField.length]; int i, k = remoteField.length; for (i = 0; i < k; i++) variable [i] = new ToolsVariable ( debugger, remoteObject, remoteField [i] ); int l = sRemoteField.length; for (i = 0; i < l; i++) variable [i + k] = new ToolsVariable ( debugger, remoteClass, sRemoteField [i] ); //S ystem.out.println ("getFields return fields " + variable + " " + variable.length); // NOI18N } oldObject = remoteObject; oldFields = variable; return variable; } catch (Exception e) { return new ToolsVariable [0]; } } }.wait (debugger.synchronizer, debugger.killer); } /** * Returns true if this variable hasn't any fields. * * @return True if this variable hasn't any fields. */ public boolean isLeaf () { return (remoteValue == null) || !(remoteValue instanceof RemoteObject); } // other methods .................................................................................... /** * I am member of field. * modifiers, type, remoteValue, parentObject */ boolean update ( String name, RemoteArray array, int index, String type ) { this.name = name + " [" + index + "]"; // NOI18N parentObject = array; this.index = index; this.type = type; modifiers = ""; // NOI18N try { remoteValue = array.getElement (index); } catch (Exception e) { return false; } update (); return true; } /** * Init for remoteObject * modifiers, type, remoteValue, parentObject */ boolean update ( RemoteField remoteField, RemoteObject parentObject ) { if (remoteField == null) return false; this.name = remoteField.getName (); this.parentObject = parentObject; try { remoteValue = parentObject.getFieldValue (name); modifiers = remoteField.getModifiers (); type = remoteField.getType ().toString (); } catch (Exception e) { return false; } update (); return true; } /** * For local variables. (locales or watch) */ void update ( String name, RemoteValue remoteValue, String type ) { this.name = name; this.remoteValue = remoteValue; this.parentObject = null; this.type = type; modifiers = ""; // NOI18N update (); } void setNull () { remoteValue = null; parentObject = null; modifiers = ""; // NOI18N type = ""; // NOI18N update (); } /** * Validate value of variable (validateIn) and fires changes. */ public void validate () { if (debugger.synchronizer == null) return; new Protector ("ToolsVariable.validate") { // NOI18N public Object protect () { validateUnsafe (); return null; } }.wait (debugger.synchronizer, debugger.killer); // deadlock prevention final PropertyChangeSupport p = pcs; SwingUtilities.invokeLater (new Runnable () { public void run () { firePropertyChange (); } }); } /** * @return true if debugger is stopped. */ public boolean canValidate () { return debugger.getState () == ToolsDebugger.DEBUGGER_STOPPED; } /** * @return true, variable can be removed from validator when debugger is finished */ public boolean canRemove () { return true; } private void validateUnsafe() { if (isCloned) { if (isObject) { value = remoteValue.toString (); checkString (); } return; } else if (index != -1) if (parentObject instanceof RemoteArray) try { remoteValue = ((RemoteArray) parentObject).getElement (index); } catch (Exception e) { } else remoteValue = null; else if (parentObject != null) try { remoteValue = parentObject.getFieldValue (name); } catch (Exception e) { } else remoteValue = null; update (); } /** * remoteValue => isObject, isArray, value, innerType */ private void update () { errorMessage = null; if (remoteValue == null) { isObject = false; isArray = false; value = null; innerType = ""; // NOI18N } else try { isObject = remoteValue.isObject (); isArray = remoteValue instanceof RemoteArray; if (isArray) { value = remoteValue.toString (); checkString (); innerType = obtainType (((RemoteArray)remoteValue).getClazz ().getName ()); } else if (isObject) { value = remoteValue.toString (); checkString (); innerType = ((RemoteObject)remoteValue).getClazz ().getName (); } else { innerType = remoteValue.typeName (); value = remoteValue.description (); // value of byte or short is returned in hexadecimal format, decimal format is required if (innerType.equals ("byte") || innerType.equals ("short")) { // NOI18N try { value = Integer.toString ((Integer.decode (value)).intValue ()); } catch (NumberFormatException e) { } } } } catch (Exception e) { // exception will be notified type = null; value = e.toString (); } } /** * PATCH: Extracts type name from a string returned by sun.tools.debug.RemoteClass.getName () for an array. */ private String obtainType (String string) { try { if (!string.startsWith("[")) // NOI18N return string; int index = string.lastIndexOf ('['); String base = ""; // NOI18N switch (string.charAt (index + 1)) { case 'I': base = "int"; break; // NOI18N case 'Z': base = "boolean"; break; // NOI18N case 'J': base = "long"; break; // NOI18N case 'F': base = "float"; break; // NOI18N case 'D': base = "double"; break; // NOI18N case 'B': base = "byte"; break; // NOI18N case 'S': base = "short"; break; // NOI18N case 'C': base = "char"; break; // NOI18N case 'L': base = string.substring (index + 2, string.length () - 1); break; // NOI18N } for (int x = 0; x <= index; x++) base = base.concat ("[]"); // NOI18N return base; } catch (IndexOutOfBoundsException e) { return string; } } private void checkString () { try { if (type.equals ("java.lang.String")) { // NOI18N AbstractVariable [] var = getFields (); int k = 0; while (k < var.length) { if (var[k].getVariableName().equals("count")) // NOI18N break; k++; } if ((k < var.length)&&(var[k].getAsText ().equals ("0"))) // NOI18N value = new String (""); // NOI18N if (value != null) value = "\"".concat (value.concat ("\"")); // NOI18N } } catch (Exception e) {} } void setValue (String v) { value = v; } // Helper methods enabling delegating in ToolsWatch ToolsDebugger getDebugger () { return debugger; } /* public String getErrorMessage () { return errorMessage; } */ void setErrorMessage (String errMessage) { errorMessage = errMessage; } RemoteValue getRemoteValue () { return remoteValue; } void setRemoteValue (RemoteValue val) { remoteValue = val; } java.lang.Object clone_protected () { return clone (); } void setError_protected (String description) { setError (description); } void firePropertyChange () { super.firePropertyChange (null, null, null); } } /* * Log * 26 Gandalf-post-FCS1.21.3.3 3/30/00 Daniel Prusa * 25 Gandalf-post-FCS1.21.3.2 3/30/00 Daniel Prusa * 24 Gandalf-post-FCS1.21.3.1 3/29/00 Daniel Prusa * 23 Gandalf-post-FCS1.21.3.0 3/28/00 Daniel Prusa * 22 Gandalf 1.21 1/14/00 Daniel Prusa NOI18N * 21 Gandalf 1.20 1/14/00 Daniel Prusa missing 'else' in * validateIn added * 20 Gandalf 1.19 1/13/00 Daniel Prusa NOI18N * 19 Gandalf 1.18 1/10/00 Jan Jancura Refresh of locales * updated * 18 Gandalf 1.17 1/5/00 Jan Jancura Bug 4276 * 17 Gandalf 1.16 1/4/00 Daniel Prusa * 16 Gandalf 1.15 1/3/00 Daniel Prusa * 15 Gandalf 1.14 12/30/99 Daniel Prusa Validator placed into * Watch * 14 Gandalf 1.13 12/28/99 Daniel Prusa Bugfix for CR 1888 * 13 Gandalf 1.12 12/21/99 Daniel Prusa Interfaces Debugger, * Watch, Breakpoint changed to abstract classes. * 12 Gandalf 1.11 11/8/99 Jan Jancura Somma classes renamed * 11 Gandalf 1.10 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 10 Gandalf 1.9 10/5/99 Jan Jancura Serialization of * debugger. * 9 Gandalf 1.8 9/15/99 Jan Jancura * 8 Gandalf 1.7 9/2/99 Jan Jancura * 7 Gandalf 1.6 7/21/99 Jan Jancura * 6 Gandalf 1.5 6/10/99 Jan Jancura * 5 Gandalf 1.4 6/9/99 Jan Jancura * 4 Gandalf 1.3 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 3 Gandalf 1.2 6/4/99 Jan Jancura * 2 Gandalf 1.1 6/4/99 Jan Jancura * 1 Gandalf 1.0 6/1/99 Jan Jancura * $ */